package org.massdeception.content.servlets.authors;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.*;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.massdeception.content.entities.PMF;
import org.massdeception.content.entities.Slide;
import org.massdeception.content.util.SlideUtils;

import com.google.appengine.api.users.User;

public class AuthorUploadSlideServlet extends AuthorServlet 
{
    private static final Logger log = Logger.getLogger(AuthorUploadSlideServlet.class.getName());

    private final String PARAM_ID = "slideId";
    
    private final String PARAM_TITLE = "title";
    
    private final String PARAM_ALT_TEXT = "alttext";
    
    private final String PARAM_PUBLISH = "publish";
    
    private final String PARAM_SLIDE = "slide";
    
    private final String PARAM_PREV_DATE = "previousDate";
    
    public void process(HttpServletRequest request, HttpServletResponse response, User user)
        throws IOException, ServletException
    {
        if ( !ServletFileUpload.isMultipartContent(request) )
        {
            response.sendError(500, "Request is not multipart and could not be processed.");
            log.log(Level.WARNING, "Request is not multipart and could not be processed.");
            return;
        }
        
        PersistenceManager pm = null;
        try
        {
        	pm = PMF.get().getPersistenceManager();
            //pm.setDetachAllOnCommit(true);
            
            // Create a factory for disk-based file items
            DiskFileItemFactory factory = new DiskFileItemFactory();
            factory.setSizeThreshold(300*1024);

            HashMap<String, String> params = new HashMap<String, String>();
            HashMap<String, byte []> files = new HashMap<String, byte []>();
            HashMap<String, String> fileNames = new HashMap<String, String>();
            
            // Create a new file upload handler
            ServletFileUpload upload = new ServletFileUpload();

            // Parse the request
            FileItemIterator iter = upload.getItemIterator(request);
            while ( iter.hasNext() ) 
            {
                FileItemStream item = iter.next();
                String name = item.getFieldName();
                InputStream stream = item.openStream();
                if (item.isFormField()) 
                {
                    String value = Streams.asString(stream);
                    params.put(item.getFieldName(), value);
                } 
                else 
                {
                    fileNames.put(name, item.getName());
                    
                    byte[] buffer = new byte[2048];
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    //int bytesread = 0;
                    //while ( stream.read(buffer) > 0 )
                    //    baos.write(buffer);
                    
                    while (true)
                    {
                        int br = stream.read(buffer);
                        if (br < 0)
                            break;
                        baos.write(buffer, 0, br);
                    }
 
                    byte [] bytes = baos.toByteArray();
                    
                    files.put(name, bytes);
                }
            }
            
            String id = params.get(PARAM_ID);
            
            Slide slide = new Slide();
            boolean edit = false;
            
            if ( (id != null) && (!"".equals(id)) )
            {
                // try to get if from the data source                
                //Key key = KeyFactory.createKey(Slide.class.getSimpleName(), Long.parseLong(id));
                //slide = (Slide) PMF.get().getPersistenceManager().getObjectById(Slide.class, key);
                slide = pm.getObjectById(Slide.class, Long.parseLong(id));

                edit = true;
                
                if ( slide == null )
                {
                	log.log(Level.WARNING, "Could not find slide with id "+id);
                	response.sendError(500, "Invalid slide Id.");
                	return;
                }
            }
            
            if ( params.containsKey(PARAM_TITLE) )
                slide.setTitle(params.get(PARAM_TITLE));
            
            if ( params.containsKey(PARAM_ALT_TEXT) )
                slide.setAltText(params.get(PARAM_ALT_TEXT));
            
            if ( params.containsKey(PARAM_PUBLISH) )
                slide.setPublishDate(SlideUtils.getNormalizedUIDate(params.get(PARAM_PUBLISH), true));
            
            if ( files.containsKey(PARAM_SLIDE) )
            {
                if ( files.get(PARAM_SLIDE).length != 0 )
                {
                    slide.setBytes(files.get(PARAM_SLIDE));
                    String name = fileNames.get(PARAM_SLIDE);
                    slide.setExtension(name.substring(name.indexOf(".")+1, name.length()));
                }
            }
            
            slide.setAuthor(user);
            slide.setUploadDate(new Date());

            if ( !edit )
            	pm.makePersistent(slide);
            else
                SlideUtils.removeSlideFromCache(Long.parseLong(params.get(PARAM_PREV_DATE)));
            
            // forward the request
            RequestDispatcher dispatcher = request.getRequestDispatcher("/authorUploadSlideSuccess.jsp");
            dispatcher.forward(request, response);
        }
        catch (Throwable t)
        {
            response.sendError(500, "Request could not be processed.");
            log.log(Level.SEVERE, "Request is not multipart and could not be processed.", t);
            return;
        }
        finally
        {
            pm.close();
        }        
    }
}